package com.xinchao.common.util;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONObject;
import com.xinchao.common.vo.huawei.HuaWeiSmsSendStatusCallBackVO;

/**
 * 
 * <p>Title: SmsUtil</p>  
 * <p>Description: 华为云短信发送Util</p>  
 * @author huangf 
 * @date 2018年8月13日
 */
@Service
public class HuaWeiSmsUtil {
	private static Logger logger = LoggerFactory.getLogger(HuaWeiSmsUtil.class);
	// ws-header-format
    private static final String WSSE_HEADER_FORMAT = "UsernameToken Username=\"%s\",PasswordDigest=\"%s\",Nonce=\"%s\",Created=\"%s\"";
    // auth-header
    private static final String AUTH_HEADER_VALUE = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\"";
    // 应用管理页面获取APP_Key
    private static final String APP_KEY = "RfNRumwt89csD1A76485KuAa2UcF";
    // 应用管理页面获取APP_Secret 
    private static final String APP_SECRET = "Dw3f7uSM3NegXU9XKlYB8d42the7";
    // 短信签名中的通道号，请从签名管理页面获取
    private static final String SENDER = "csms18090326";
    // 应用管理页面获取APP接入地址，替换url中的ip地址和端口
    private static final String URL = "https://117.78.29.66:10443/sms/batchSendSms/v1";
    
    /**
     * 发送短信无需发送状态回调
     * @param templateId
     * @param templateParas 【请按实际参数的顺序占位】
     * @param mobile
     */
    public static Map<String,Object> sendSMS(String templateId, String templateParas, String mobile) { 
    	return send( templateId,  templateParas,  mobile, null);
    }
    
    /**
     * 发送短信无需发送状态回调
     * @param templateId
     * @param templateParas 【请按实际参数的顺序占位】
     * @param mobile
     */
    public static Map<String,Object> sendSMS(String templateId, String templateParas, String mobile, String sendStatusCallBackUrl) { 
    	return send( templateId,  templateParas,  mobile, sendStatusCallBackUrl);
    }
    
    /**
     *  华为云短信发送
     * @param templateId  模版id
     * @param templateParas 动态替换参数（jsonString） 
     *   //如模板内容为“您有${NUM_2}件快递请到${TXT_32}领取”时，templateParas可填写为[\"3\",\"人民公园正门\"]
         //双变量示例：String templateParas = "[\"3\",\"人民公园正门\"]";
     * @param mobile
     * @throws Exception 
     * @throws UnsupportedEncodingException 
     * @throws ClientProtocolException 
     */
	static Map<String,Object> send(String templateId, String templateParas, String mobile, String sendStatusCallBackUrl) {

		String body = buildRequestBody(SENDER, mobile, templateId, templateParas, sendStatusCallBackUrl);
		logger.debug("body is " + body);

		String wsseHeader = buildWsseHeader(APP_KEY, APP_SECRET);
		logger.debug("wsse header is " + wsseHeader);

		HttpResponse response;
		Map<String,Object> result = new HashMap<>();
		try {
			CloseableHttpClient client = HttpClients.custom()
					.setSSLContext(
							new SSLContextBuilder().loadTrustMaterial(null, (x509CertChain, authType) -> true).build())
					.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE).build();

			response = client.execute(RequestBuilder.create("POST").setUri(URL)
					.addHeader(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded")
					.addHeader(HttpHeaders.AUTHORIZATION, AUTH_HEADER_VALUE).addHeader("X-WSSE", wsseHeader)
					.setEntity(new StringEntity(body)).build());
			JSONObject parse = (JSONObject) JSONObject.parse(EntityUtils.toString(response.getEntity()));
			HuaWeiSmsSendStatusCallBackVO sendStatusCallBackVO = parse.toJavaObject(HuaWeiSmsSendStatusCallBackVO.class);
			if ( sendStatusCallBackVO != null && sendStatusCallBackVO.getResult() != null ) {
				result.put("smsMsgId", sendStatusCallBackVO.getResult().get(0).getSmsMsgId());
			}
			result.put("smsMsgId", "");
		} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | IOException e) {
			e.printStackTrace();
			logger.error("华为云短信通道发送失败：" + e.getMessage(),e);
		}
		return result;
	}
    
    static String buildRequestBody(String sender, String receiver, String templateId, String templateParas,
                                   String statusCallbackUrl) {

        List<NameValuePair> keyValues = new ArrayList<>();

        keyValues.add(new BasicNameValuePair("from", sender));
        keyValues.add(new BasicNameValuePair("to", receiver));
        keyValues.add(new BasicNameValuePair("templateId", templateId));
        keyValues.add(new BasicNameValuePair("templateParas", templateParas));
        keyValues.add(new BasicNameValuePair("statusCallback", statusCallbackUrl));

        return URLEncodedUtils.format(keyValues, StandardCharsets.UTF_8);
    }

    static String buildWsseHeader(String appKey, String appSecret) {
        SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss'Z'");
        String time = sdf.format(new Date());
        String nonce = UUID.randomUUID().toString().replace("-", "");

        byte[] passwordDigest = DigestUtils.sha256(nonce + time + appSecret);
        String hexDigest = Hex.encodeHexString(passwordDigest);
        String passwordDigestBase64Str = Base64.encodeBase64String(hexDigest.getBytes(Charset.forName("utf-8")));
        return String.format(WSSE_HEADER_FORMAT, appKey, passwordDigestBase64Str, nonce, time);
    }
    
    public static void main(String[] args) throws Exception{
        String receiver = "13540154422";
        String statusCallBack = "http://114.115.216.181:8090/sms/callback";
        String templateId = "d1672ec7a15c4600a62a41d5abf38971";
        String[] params = { "xcm-client-api","10.200.110.244:8088"};
        
        String templateParas = JSONObject.toJSONString(params);//"[\"334455\"]";
        System.out.println(templateParas);
        //templateParas = templateParas.replaceAll("\"", "\\\\\"");
        //templateParas =  "[\"1111\"]";
        System.out.println(templateParas);
        sendSMS(templateId, templateParas, receiver,statusCallBack);
    }
}
